import axios from 'axios';
import QS from 'query-string';
import { useDebounceFn } from '@vueuse/core';

import router from '/@/router/index';
import { useToken, useUserId } from '/@/hooks/index';

// import { getFingerprint } from './fingerprint';
// import { UploadBusinessType } from '../types/uploadTypes';
import { useLoadingStore } from '../store';
import { RequestOptions } from '../types/requestTypes';
import { compressImage } from './compressImage';
import { BASE_URL, NotifyError } from './index';
import { CURRENT_LANG, i18nTranslate } from '../i18n';

const showErrorMessage = (content = '') => NotifyError(content);

// loading数量栈
const LOADING_STACK = <any[]>[];

/**
 * 请求开始时添加loading入栈
 */
const startLoading = (loading = true) => {
  const loadingStore = useLoadingStore();
  if (loading) {
    LOADING_STACK.push();
    loadingStore.onToggleLoading(true);
  }
};

/**
 * 请求结束时出栈，如果栈空，则不再展示loading
 */
const endLoading = (loading = true) => {
  const loadingStore = useLoadingStore();
  if (loading) {
    // 延时防抖处理，避免loading多次重复出现
    useDebounceFn(() => {
      LOADING_STACK.pop();
      if (!LOADING_STACK.length) {
        loadingStore.onToggleLoading(false);
      }
    }, 200)();
  }
};

// 创建axios实例
const service = axios.create({
  baseURL: BASE_URL, // api的base_url
  timeout: 30 * 1000, // 请求超时时间，ms
  withCredentials: true,
  paramsSerializer: {
    serialize: (params) => QS.stringify(params),
  },
  headers: {
    'Content-Type': 'application/json',
  },
});

// request拦截器
service.interceptors.request.use(
  async (config) => {
    const { getToken } = useToken();
    const token = getToken();
    const { getUserId } = useUserId();
    const userId = getUserId();
    if (token) {
      // 让每个请求携带自定义token 请根据实际情况自行修改
      config.headers['authorization'] = token;
      config.headers['token'] = token;
      config.headers['userId '] = userId;
    }

    // 设备类型
    config.headers['deviceType'] = 'h5';
    // 系统语言
    config.headers['languageCode'] = CURRENT_LANG;
    // 手机型号
    config.headers['deviceModel'] = window.navigator.userAgent;
    // 浏览器唯一编码
    // config.headers['deviceCode'] = await getFingerprint();
    return config;
  },
  (error) => {
    // Do something with request error
    Promise.reject(error);
  },
);

// respone拦截器
service.interceptors.response.use(
  (response) => {
    const { errorMessage, status, result } = response.data;

    // 请求 result
    if (status) {
      const { setToken } = useToken();
      const { setUserId } = useUserId();
      // 登录成功后会返回token
      if (result && result.token) {
        setToken(`${result.token}`);
        setUserId(`${result.id}`);
      }
      switch (status) {
        // 正常请求
        case 'SUCCEED':
          return result === undefined ? null : result;
        default:
          showErrorMessage(errorMessage);
          return Promise.reject(errorMessage);
      }
    }

    // 请求 流数据
    return response.data;
  },
  (error) => {
    if (error && error.response) {
      const { data } = error.response;
      switch (data.errorCode) {
        // 登录失效
        case 'SYS.0015':
          clearInfoAfterSignOut();
          return Promise.reject(error);
        case 'SYS.0000':
          showErrorMessage(i18nTranslate('ThesystemisundermaintenancePleasetryagainlater'));
          return Promise.reject(error);
        default:
          showErrorMessage(data.errorMessage || data.error);
          return Promise.reject(error);
      }
    } else {
      // 开发环境触发，网络异常或服务异常，提示问题即可
      showErrorMessage(i18nTranslate('ThesystemisundermaintenancePleasetryagainlater'));
      // clearInfoAfterSignOut();
    }
    return Promise.reject(error);
  },
);

/**
 * 退出登录
 */
export const clearInfoAfterSignOut = (navToSignIn = true) => {
  // 清除登录相关数据，但是不能清除语言和暗黑模式的设置
  const { setToken } = useToken();
  const { setUserId } = useUserId();
  setToken('');
  setUserId('');
  // 清除用户信息
  // 前往登录页
  if (navToSignIn) {
    router.replace('/');
  }
};

/**
 * post类型，get传参方式，发送请求，大部分请求都是这种
 * @param url
 * @param params
 * @param headers 有部分参数会放到headers中
 * @param options 部分请求的配置，比如是否需要全局处理loading
 * @returns
 */
export const postParams = async (
  url: string,
  params = {},
  headers = {},
  options = <RequestOptions>{ showLoading: true },
) => {
  const { showLoading } = options;
  try {
    startLoading(showLoading);
    const res = await service.post(url, null, {
      params,
      headers: {
        ...headers,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    });
    endLoading(showLoading);
    return Promise.resolve(res);
  } catch (error) {
    endLoading(showLoading);
    return Promise.reject(error);
  }
};

/**
 * post类型，get传参方式，发送请求，大部分请求都是这种
 * @param url
 * @param params
 * @param headers 有部分参数会放到headers中
 * @param options 部分请求的配置，比如是否需要全局处理loading
 * @returns
 */
export const getParams = async (url: string, params = {}, headers = {}) => {
  try {
    const res = await service.get(url, {
      params,
      headers: {
        ...headers,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    });

    return Promise.resolve(res);
  } catch (error) {
    return Promise.reject(error);
  }
};

/**
 * post类型，表单传参方式，发送请求
 * @param url
 * @param data
 * @param headers 有部分参数会放到headers中
 * @param options 部分请求的配置，比如是否需要全局处理loading
 * @returns
 */
export const postQuery = async (
  url: string,
  data = {},
  headers = {},
  options = <RequestOptions>{ showLoading: true },
) => {
  const { showLoading } = options;
  try {
    startLoading(showLoading);
    const res = await service.post(url, data, {
      headers: {
        ...headers,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    });
    endLoading(showLoading);
    return Promise.resolve(res);
  } catch (error) {
    endLoading(showLoading);
    return Promise.reject(error);
  }
};

/**
 *  post类型，json格式传参
 * @param url
 * @param data 参数对象
 * @param headers 有部分参数会放到headers中
 * @returns
 */
export const postJson = async (
  url: string,
  data = {},
  headers = {},
  options = <RequestOptions>{ showLoading: true },
) => {
  const { showLoading } = options;
  try {
    startLoading(showLoading);
    const _headers = { 'Content-Type': 'application/json; charset=utf8;' };
    if (headers) {
      Object.assign(_headers, headers);
    }

    const res = await service.post(url, data, {
      headers: _headers,
    });
    endLoading(showLoading);
    return Promise.resolve(res);
  } catch (error) {
    endLoading(showLoading);
    return Promise.reject(error);
  }
};

// 上传服务
const UPLOAD_URL = '/data/fileUpload';

/**
 * 上传图片接口
 * @param multipartFile
 * @param business
 * @returns
 */
export const upload = async (
  multipartFile: File,
  options = <RequestOptions>{ showLoading: true },
) => {
  const { showLoading } = options;
  try {
    startLoading(showLoading);

    let _file = multipartFile;
    // // 对图片进行压缩，避免上传过大的图片
    if (multipartFile.type.includes('image')) {
      _file = await compressImage(multipartFile);
    }

    const res = await service.postForm(UPLOAD_URL, {
      file: _file,
    });
    endLoading(showLoading);
    return Promise.resolve(res);
  } catch (error) {
    endLoading(showLoading);
    return Promise.reject(error);
  }
};

export default service;
